home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1994…tember: Reference Library / Dev.CD Sep 94.toast / Periodicals / develop / develop Issue 6 / develop 6 code / TCP / NewsWatcher / NewsWatcher 2.0d15 source / source / ftp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-08-17  |  8.0 KB  |  347 lines  |  [TEXT/KAHL]

  1. /*----------------------------------------------------------------------------
  2.  
  3.     ftp.c
  4.  
  5.     This handle all transactions with FTP servers.
  6.     
  7.     Portions copyright © 1990, Apple Computer.
  8.     Portions copyright © 1993, Northwestern University.
  9.  
  10. ----------------------------------------------------------------------------*/
  11.  
  12. #include <string.h>
  13. #include <stdio.h>
  14.  
  15. #include "MacTCPCommonTypes.h"
  16. #include "TCPPB.h"
  17.  
  18. #include "glob.h"
  19. #include "dlgutil.h"
  20. #include "ftp.h"
  21. #include "tcp.h"
  22. #include "util.h"
  23.  
  24.  
  25. static unsigned long gControlConnectionId;
  26. static unsigned long gDataConnectionId;
  27. static Ptr gBuffer;
  28. static Boolean gAlreadyGot226;
  29.  
  30.  
  31. /* Abort aborts a transaction with an FTP server. */
  32.  
  33. static void Abort (void)
  34. {
  35.     if (gControlConnectionId != 0) {
  36.         AbortConnection(gControlConnectionId);
  37.         ReleaseStream(gControlConnectionId);
  38.     }
  39.     if (gDataConnectionId != 0) {
  40.         AbortConnection(gDataConnectionId);
  41.         ReleaseStream(gDataConnectionId);
  42.     }
  43.     MyDisposPtr(gBuffer);
  44. }
  45.  
  46.  
  47. /* Init initializes a transaction with an FTP server. */
  48.  
  49. static Boolean Init (char *host, char *user, char *pswd,
  50.     char *file, char *cmd)
  51. {
  52.     CStr255 sendData[4];
  53.     unsigned long addr;
  54.     unsigned long myAddr;
  55.     unsigned short length;
  56.     OSErr err;
  57.     TCPiopb *pBlock;
  58.     unsigned short localPort;
  59.     Ptr p,pEnd;
  60.     char *serverCommand = nil;
  61.     
  62.     gControlConnectionId = gDataConnectionId = 0;
  63.     gBuffer = nil;
  64.     pBlock = nil;
  65.     
  66.     /* Get host address. */
  67.  
  68.     if (IPNameToAddr(host, &addr) != noErr) {
  69.         if (err != -1) ErrorMessage("Could not get host address.");
  70.         goto exit3;
  71.     }
  72.     
  73.     /* Allocate data buffer. */
  74.     
  75.     gBuffer = MyNewPtr(kBufLen);
  76.     if ((err = MyMemErr()) != noErr) goto exit1;
  77.     
  78.     /* Create and open control stream connecton. */
  79.     
  80.     if ((err = CreateStream(&gControlConnectionId,kBufLen)) != noErr) goto exit1;
  81.     if ((err = OpenConnection(gControlConnectionId,addr,kFTPPort,20)) != noErr) {
  82.         if (err != -1) ErrorMessage("Could not open connection to host.");
  83.         goto exit3;
  84.     }
  85.     length = kBufLen;
  86.     if ((err = RecvData(gControlConnectionId,gBuffer,&length,true)) != noErr) goto exit1;
  87.     if (length < 3 || *gBuffer != '2') goto exit2;
  88.     
  89.     /* Send USER command. */
  90.     
  91.     strcpy(sendData[0],"USER ");
  92.     strcpy(sendData[1],user);
  93.     strcpy(sendData[2],CRLF);
  94.     if ((err = SendMultiData(gControlConnectionId,sendData,3)) != noErr) goto exit1;
  95.     length = kBufLen;
  96.     if ((err = RecvData(gControlConnectionId,gBuffer,&length,true)) != noErr) goto exit1;
  97.     if (length < 3 || *gBuffer != '3') goto exit4;
  98.     
  99.     /* Send PASS command. */
  100.     
  101.     strcpy(sendData[0],"PASS ");
  102.     strcpy(sendData[1],pswd);
  103.     strcpy(sendData[2],CRLF);
  104.     if ((err = SendMultiData(gControlConnectionId,sendData,3)) != noErr) goto exit1;
  105.     length = kBufLen;
  106.     if ((err = RecvData(gControlConnectionId,gBuffer,&length,true)) != noErr) goto exit1;
  107.     if (length < 3 || *gBuffer != '2') goto exit4;
  108.     
  109.     /* Create and open data stream connection. */
  110.     
  111.     if ((err = CreateStream(&gDataConnectionId,kBufLen)) != noErr) goto exit1;
  112.     if ((err = AsyncWaitForConnection(gDataConnectionId,0,0,0,0,&pBlock)) !=
  113.         noErr) goto exit1;
  114.         
  115.     /* Wait for MacTCP to assign port number. */
  116.         
  117.     while ((localPort = pBlock->csParam.open.localPort) == 0 && GiveTime());
  118.     if (gCancel) goto exit3;
  119.  
  120.     /* Send PORT command. */
  121.     
  122.     if ((err = GetMyIPAddr(&myAddr)) != noErr) goto exit1;
  123.     sprintf(sendData[0],"PORT %hu,%hu,%hu,%hu,%hu,%hu",
  124.         (unsigned short)((myAddr>>24)&0xff), 
  125.         (unsigned short)((myAddr>>16)&0xff), 
  126.         (unsigned short)((myAddr>>8)&0xff), 
  127.         (unsigned short)(myAddr&0xff),
  128.         (unsigned short)((localPort>>8)&0xff), 
  129.         (unsigned short)(localPort&0xff));
  130.     strcpy(sendData[1],CRLF);
  131.     serverCommand = "PORT";
  132.     if ((err = SendMultiData(gControlConnectionId,sendData,2)) != noErr) goto exit1;
  133.     length = kBufLen;
  134.     if ((err = RecvData(gControlConnectionId,gBuffer,&length,true)) != noErr) goto exit1;
  135.     if (length < 3 || *gBuffer != '2') goto exit2;
  136.     
  137.     /* Send RETR or STOR command. */
  138.     
  139.     strcpy(sendData[0],cmd);
  140.     strcpy(sendData[1]," ");
  141.     strcpy(sendData[2],file);
  142.     strcpy(sendData[3],CRLF);
  143.     serverCommand = cmd;
  144.     if ((err = SendMultiData(gControlConnectionId,sendData,4)) != noErr) goto exit1;
  145.     length = kBufLen;
  146.     if ((err = RecvData(gControlConnectionId,gBuffer,&length,true)) != noErr) goto exit1;
  147.     if (length < 3 || *gBuffer != '1') goto exit2;
  148.     
  149.     /* If the timing is just right, it is possible that the final 226 "data transfer
  150.        complete" message arrived as part of the buffer just received. We must check 
  151.        for this. */
  152.        
  153.     p = gBuffer;
  154.     pEnd = gBuffer+length-3;
  155.     gAlreadyGot226 = false;
  156.     while (p < pEnd ) {
  157.         if (*p == CR && *(p+1) == LF) {
  158.             p += 2;
  159.             length = pEnd - p;
  160.             if (length < 3 || *p != '2') {
  161.                 MailOrFTPServerErrorMessage(p);
  162.                 goto exit3;
  163.             }
  164.             gAlreadyGot226 = true;
  165.             break;
  166.         }
  167.         p++;
  168.     }
  169.     
  170.     /* Wait for server to open its end of the data stream connection. */
  171.     
  172.     while (pBlock->ioResult > 0 && GiveTime());
  173.     err = gCancel ? -1 : pBlock->ioResult;
  174.     if (err != noErr) goto exit1;
  175.     MyDisposPtr((Ptr)pBlock);
  176.     
  177.     return true;
  178.     
  179. exit1:
  180.  
  181.     UnexpectedErrorMessage(err);
  182.     goto exit3;
  183.     
  184. exit2:
  185.  
  186.     MailOrFTPServerErrorMessage(gBuffer);
  187.     
  188. exit3:
  189.  
  190.     Abort();
  191.     MyDisposPtr((Ptr)pBlock);
  192.     return false;
  193.     
  194. exit4:
  195.  
  196.     ErrorMessage("Invalid username or password.");
  197.     goto exit3;
  198. }
  199.  
  200.  
  201. /* Term terminates a transaction with an FTP server. */
  202.  
  203. static Boolean Term (char *cmd, Boolean get)
  204. {
  205.     CStr255 commStr;
  206.     unsigned short length;
  207.     OSErr err;
  208.     char *serverCommand;
  209.     
  210.     /* Close data stream. */
  211.     
  212.     if ((err = CloseConnection(gDataConnectionId, get)) != noErr) goto exit1;
  213.     if ((err = ReleaseStream(gDataConnectionId)) != noErr) goto exit1;
  214.     
  215.     /* Check for final 226 "data transfer complete" reply to RETR or STOR command. */
  216.     
  217.     serverCommand = cmd;
  218.     if (!gAlreadyGot226) {
  219.         length = kBufLen;
  220.         if ((err = RecvData(gControlConnectionId,gBuffer,&length,true)) != noErr) goto exit1;
  221.         if (length < 3 || *gBuffer != '2') goto exit2;
  222.     }
  223.     
  224.     /* Send QUIT command on control stream. */
  225.     
  226.     strcpy(commStr,"QUIT");
  227.     strcat(commStr,CRLF);
  228.     serverCommand = "QUIT";
  229.     if ((err = SendData(gControlConnectionId,commStr,6)) != noErr) goto exit1;
  230.     length = kBufLen;
  231.     if ((err = RecvData(gControlConnectionId,gBuffer,&length,true)) != noErr) goto exit1;
  232.     if (length < 3 || *gBuffer != '2') goto exit2;
  233.     
  234.     /* Close control stream. */
  235.  
  236.     if ((err = CloseConnection(gControlConnectionId, true)) != noErr) goto exit1;
  237.     if ((err = ReleaseStream(gControlConnectionId)) != noErr) goto exit1;
  238.  
  239.     /* Dispose the buffer. */
  240.     
  241.     MyDisposPtr(gBuffer);
  242.     return true;
  243.     
  244. exit1:
  245.  
  246.     UnexpectedErrorMessage(err);
  247.     goto exit3;
  248.     
  249. exit2:
  250.  
  251.     MailOrFTPServerErrorMessage(gBuffer);
  252.     
  253. exit3:
  254.  
  255.     Abort();
  256.     return false;
  257. }
  258.  
  259.  
  260. /* FTPGetFile gets a file from a host. */    
  261.     
  262. Boolean FTPGetFile (char *host, char *user, char *pswd, char *file, Handle data)
  263. {
  264.     unsigned short length;
  265.     long size, allocated;
  266.     OSErr err;
  267.     Ptr p,pEnd,q;
  268.  
  269.     if (!Init(host,user,pswd,file,"RETR")) return false;
  270.     
  271.     MySetHandleSize(data, kBufLen);
  272.     size = 0;
  273.     allocated = kBufLen;
  274.     
  275.     while (true) {
  276.         length = kBufLen;
  277.         if ((err = RecvData(gDataConnectionId,gBuffer,&length,true)) != noErr) break;
  278.         if (size + length > allocated) {
  279.             allocated += kBufLen;
  280.             MySetHandleSize(data, allocated);
  281.         }
  282.         BlockMove(gBuffer, *data + size, length);
  283.         size += length;
  284.     }
  285.     if (err != connectionClosing && err != connectionTerminated) goto exit1;
  286.     
  287.     p = q = *data;;
  288.     pEnd = *data + size;
  289.     while (p < pEnd) {
  290.         if (*p == CR && *(p+1) == LF) {
  291.             *q++ = CR;
  292.             p += 2;
  293.         } else {
  294.             *q++ = *p++;
  295.         }
  296.     }
  297.     size = q - *data;
  298.     MySetHandleSize(data, size + 1);
  299.     *(*data+size) = 0;
  300.  
  301.     return Term("RETR", true);
  302.     
  303. exit1:
  304.  
  305.     UnexpectedErrorMessage(err);
  306.     Abort();
  307.     return false;
  308. }
  309.  
  310.  
  311. /* FTPPutFile sends a file to a host. */    
  312.     
  313. Boolean FTPPutFile (char *host, char *user, char *pswd, char *file, Ptr data, long size)
  314. {
  315.     OSErr err;
  316.     Ptr p,pEnd,q,qEnd;
  317.  
  318.     if (!Init(host,user,pswd,file,"STOR")) return false;
  319.     
  320.     p = data;
  321.     pEnd = data + size;
  322.     while (p < pEnd) {
  323.         q = gBuffer;
  324.         qEnd = q + kBufLen - 1;
  325.         while (p < pEnd && q < qEnd) {
  326.             if (*p == CR) {
  327.                 *q++ = CR;
  328.                 *q++ = LF;
  329.                 p++;
  330.             } else {
  331.                 *q++ = *p++;
  332.             }
  333.         }
  334.         if (q > gBuffer) {
  335.             if ((err = SendData(gDataConnectionId,gBuffer,q-gBuffer)) != noErr) goto exit1;
  336.         }
  337.     }
  338.     
  339.     return Term("STOR", false);
  340.     
  341. exit1:
  342.  
  343.     UnexpectedErrorMessage(err);
  344.     Abort();
  345.     return false;
  346. }
  347.